package com.jse.jakarta;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Map;

import com.jse.Fs;
import com.jse.Js;
import com.jse.Jse;
import com.jse.Lang;
import com.jse.Log;
import com.jse.Strings;
import com.jse.Tuple;
import com.jse.jdbc.Pager;
import com.jse.json.JsonObject;

import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

public class JseServlet extends HttpServlet{

	private static final long serialVersionUID = 1L;
	
	private final static Log log=Log.get("jseservlet");
	
	@Override
	public void init(ServletConfig conf) throws ServletException {
		try {
			Web.servletInit(conf);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException {
		if(!Web.ipCheck(req, resp))return;//IP功能
		Web.cors(req,resp);//设置跨域
		req.setCharacterEncoding(Jse.encoding);
		resp.setCharacterEncoding(Jse.encoding);
		String url=Strings.def(req.getServletPath(),req.getPathInfo());//访问Url
		String suffix=Fs.suffix(url);//后缀
		if(Lang.startsWith(url,Web.STATIC_PRIFIX)||Lang.endsWith(suffix.toLowerCase(),Web.STATIC_SUFFIX)) {
			if(Web.staticDispatcher!=null)Web.staticDispatcher.forward(req,resp);
			else View.staticforward.render(req,resp,null);return;//静态文件转发
		}
		ScopedValue.runWhere(Web.RQRS,new Tuple<HttpServletRequest,HttpServletResponse>(req,resp),()->{
			if(!Web.filter(req,resp,url,true))return;//true已被过滤
			long starttime=System.currentTimeMillis();
			int status=200;
			try {
				String mapping=url.substring(0,url.length()-suffix.length()-1).replaceAll("/$","/index");
				if(url.startsWith("/jse")){
					jse(req,resp,url,suffix);
					return;
				}
				Object reg=Web.REGEX_FUNS.isEmpty()?null:Web.REGEX_FUNS.keySet().parallelStream().filter(x->Jse.MATCHER.match(x,mapping)).findAny().get();
				if(Web.FIXED_FUNS.containsKey(mapping)){//固定映射匹配
					var t=Web.FIXED_FUNS.get(mapping);
					View.ret.render(req, resp,Js.cFun(t.a(),t.b(),t.c(),"main",Web.tbl(req,resp,url),req,resp));
				}else if(Web.REGEX_FUNS.containsKey(reg)) {
					var t=Web.REGEX_FUNS.get(mapping);
					View.ret.render(req, resp,Js.cFun(t.a(),t.b(),t.c(),"main",Web.tbl(req,resp,url),req,resp));
				}else 
				if("vue".equals(suffix)){
					vue(req,resp,url,suffix);
				}else if("".equals(suffix)||"html".equals(suffix)){//后缀空
					empty(req,resp,url,suffix);
				}else {
					var webapp=Jse.webapp(req.getServerName());
					var p=Path.of(webapp,url);
					if(Files.exists(p)) {
						Web.staticDispatcher.forward(req,resp);return;
					}
					var jspath=Jse.jspath(req.getServerName());
					var js=Path.of(jspath,mapping+".js");
					if(Files.exists(js)){
						View.ret.render(req,resp,Js.cFun(js,suffix,req,resp));
					}
				}
				Web.filter(req,resp,url,false);//执行后置处理
				if(!resp.isCommitted()) {//还没有flush处理 可以继续out
					//System.out.println(url+" not flush!"+resp.getContentType());
	    		}
			} catch (Exception e) {
				status=500;
				e.printStackTrace();
				if(!resp.isCommitted()) {
					if(e.getCause()==null) {
						try {
							View.err.render(req, resp,"runtimeExecption:"+e.getMessage());
						} catch (ServletException | IOException e1) {
							throw new RuntimeException(e1);
						}
					}else {
						try {
							View.err.render(req, resp,e.getCause().getClass().getSimpleName()+":"+e.getMessage());
						} catch (ServletException | IOException e1) {
							throw new RuntimeException(e1);
						}
					}
				}
			}finally {
				log.info("%s:%d %s\t%dms",req.getMethod(),status,req.getServletPath(),(System.currentTimeMillis()-starttime));
			}
		});
		
	}
	
	private void jse(HttpServletRequest req,HttpServletResponse resp
			,String url,String suffix) throws ServletException, IOException {//默认空后缀
		if(url.equals("/jse")) {
			Js.execute("load('classpath:jse.js')");
			View.text.render(req, resp,"jse ");
		}else if(url.equals("/jse/up")) {
			View.json.render(req, resp,Web.tbl(req,resp,url));
		}else if(url.equals("/jse/code")) {//code环境
			View.html.render(req, resp,Web.tbl(req,resp,url));
		}else if(url.equals("/jse/log")) {//日志
			View.html.render(req, resp,Web.tbl(req,resp,url));
		}else if(url.equals("/jse/gitee")) {//gitee
			View.json.render(req, resp,Js.fun("gitee",Web.tbl(req,resp,url)));
		}
		else if(url.startsWith("/jse/captcha")) {//暂时简单实现
			var code=url.substring(12);
			if(code.length()>1){code=code.substring(1);}
			else code=req.getParameter("code");
			View.captcha.render(req, resp,code);
		}
	}
	
	private void empty(HttpServletRequest req,HttpServletResponse resp
			,String url,String suffix) throws ServletException, IOException {//默认空后缀
		var jspath=Jse.jspath(req.getServerName());
		JsonObject tbl=Web.tbl(req,resp,url);//转换参数
		String mapping=Web.mapping(url,suffix,tbl);//处理/id
		req.setAttribute("p",tbl);
		var webapp=Jse.webapp(req.getServerName());
		var js=Path.of(jspath+mapping+".js");
		Object obj=null;
		if(Files.exists(js)) {
			try {
				obj=ScopedValue.where(Web.RQRS,new Tuple<HttpServletRequest,HttpServletResponse>(req,resp))
				.call(()->{return Js.cFun(js,"main",new Object[]{tbl,req,resp});});
			} catch (Exception e) {throw new RuntimeException(e);}
		}
		var ht=Lang.def(req.getAttribute("@page"),mapping+".html");
		var htm=webapp+ht;
		var htmm=webapp+"/m"+ht;//手机端页面
		if(obj instanceof View v)v.render(req, resp,null);
		else if(Files.exists(Path.of(htm))) {
			req.setAttribute("obj",obj);View.tpl.render(req,resp,htm);
		}else if(Lang.isMobile(req.getHeader("user-agent"))&&Files.exists(Path.of(htmm))) {
			req.setAttribute("obj",obj);View.tpl.render(req,resp,htmm);
		}else if(Files.exists(Path.of(jspath,mapping+".vue"))) {
			var s=Fs.readString(jspath,mapping+".vue",Map.of("tpl","js","p",tbl));
			View.text.render(req,resp,s);
		}else if(Files.exists(Path.of(webapp,mapping+".vue"))) {
			var s=Fs.readString(webapp,mapping+".vue",Map.of("tpl","js","p",tbl));
			View.text.render(req,resp,s);
		}else if(Files.exists(Path.of(jspath+mapping+".html"))) {
			View.tpl.render(req, resp,jspath+mapping+".html");
		}
		else if(obj instanceof Map||obj instanceof Collection||obj instanceof Pager) {
			View.json.render(req, resp, obj);
		}else if(obj instanceof String s) {
			View.str.render(req, resp,s);
		}
		else {
			View.not.render(req,resp,null);
		}
	}
	private void vue(HttpServletRequest req,HttpServletResponse resp
			,String url,String suffix) throws ServletException, IOException {//处理vue
		JsonObject tbl=Web.tbl(req,resp,url);//转换参数
		String mapping=Web.mapping(url,suffix,tbl);//处理/id
		var jspath=Jse.jspath(req.getServerName());
		var webapp=Jse.webapp(req.getServerName());
		var vue=Path.of(jspath,mapping.concat(".vue"));
		if(Files.exists(vue)) {
			var s=Fs.readString(jspath,mapping.concat(".vue"),Map.of("tpl","js","p",tbl));
			View.text.render(req,resp,s);
		}
		vue=Path.of(webapp,mapping+".vue");
		if(Files.exists(vue)){
			var s=Fs.readString(webapp,mapping.concat(".vue"),Map.of("tpl","js","p",tbl));
			View.text.render(req,resp,s);
		}
	}
	
	public static void main(String[] args) {
		System.out.println("/xaa/xx".replaceAll("/$","/index"));
	}
}
